package com.xbongbong.paas.script.controller;

import com.alibaba.dingtalk.openapi.exception.OApiException;
import com.alibaba.dingtalk.openapi.helper.AuthHelper;
import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.dingtalk.openapi.helper.EventChangeHelper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.BaseVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.script.pojo.dto.DingtalkReRegistCallBackDTO;
import com.xbongbong.pro.script.pojo.dto.DingtalkRegistCallbackDTO;
import com.xbongbong.sys.model.CompanyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 钉钉回调相关处理（解除/重新注册）
 *
 * @author kaka
 * @version v1.0
 * @date 2020/4/24 15:28
 * @since v1.0
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/script/dingtalk")
public class DingtalkCallBackController {

    private static final Logger LOG = LoggerFactory.getLogger(DingtalkCallBackController.class);

    @Resource
    private AuthHelper authHelper;
    @Resource
    private CompanyModel companyModel;
    @Resource
    private ProBaseConfig proBaseConfig;

    @RequestMapping(value = "/eventChange/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String eventChangeDelete(@RequestBody @Valid BaseDTO baseDTO, BindingResult br) throws XbbException {
        XbbResponse<BaseVO> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            String corpid = baseDTO.getCorpid();
            try {
                String accessToken = authHelper.getAccessToken(corpid);
                EventChangeHelper.deleteEventChange(accessToken);
                response = new XbbResponse<>(new BaseVO());
            } catch (OApiException e) {
                LOG.error("删除钉钉事件注册失败", e);
                response = new XbbResponse<>(new XbbException(e.getErrCode(), e.getErrMsg()));
            }
        }

        return JSON.toJSONString(response);
    }


    @RequestMapping(value = "/eventChange/register", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String eventChangeRegister(@RequestBody @Valid BaseDTO baseDTO, BindingResult br) throws XbbException {
        XbbResponse<BaseVO> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            String corpid = baseDTO.getCorpid();
            // 回调地址
            String url = Env.LOCAL_URL + Env.CALL_BACK_URL;
            List<String> callBackTag = getCallBackTag();
            try {
                String accessToken = authHelper.getAccessToken(corpid);
                EventChangeHelper.registerEventChange(accessToken,
                        callBackTag, Env.TOKEN, Env.ENCODING_AES_KEY, url);
                response = new XbbResponse<>(new BaseVO());
            } catch (OApiException e) {
                LOG.error("注册钉钉事件回调失败", e);
                response = new XbbResponse<>(new XbbException(e.getErrCode(), e.getErrMsg()));
            }
        }

        return JSON.toJSONString(response);
    }

    @RequestMapping(value = "/eventChange/registers", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String eventChangeRegister(@RequestBody @Valid DingtalkRegistCallbackDTO dingtalkRegistCallbackDTO, BindingResult br) throws XbbException {
        XbbResponse<BaseVO> response = new XbbResponse<>(new BaseVO());;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            LOG.info("回调注册开始");
            List<String> corpidList = dingtalkRegistCallbackDTO.getCorpidList();
            if ( CollectionsUtil.isEmpty(corpidList) ) {
                corpidList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            }
            // 回调地址
            String url = Env.LOCAL_URL + Env.CALL_BACK_URL;
            List<String> callBackTag = getCallBackTag();
            List<JSONObject> failsCorpidList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            LOG.info("回调注册开始"+corpidList.size());
            int i = 1;
            for ( String str : corpidList ) {
                LOG.info("回调注册进行中"+i+"/"+corpidList.size());
                String accessToken = null;
                // 解除注册的回调事件，分开try catch是为了防止解除的错误导致后面的注册事件失败
                try {
                    accessToken = authHelper.getAccessToken(str);
                    EventChangeHelper.deleteEventChange(accessToken);
                } catch (OApiException e) {
                    if (e.getErrCode() == 71007) {
                        LOG.warn("回调地址已不存在！不需要删除,corpid = " + str);
                    } else {
                        LOG.error("解除注册的回调事件时出现了其他错误", e);
                    }

                }
                try {
                    EventChangeHelper.registerEventChange(accessToken,
                            callBackTag, Env.TOKEN, Env.ENCODING_AES_KEY, url);
                    i++;
                } catch (OApiException e) {
                    LOG.error("注册钉钉事件回调失败", e);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(str,e.getErrMsg());
                    failsCorpidList.add(jsonObject);
                }
            }
            LOG.info("回调注册结束"+i+"/"+corpidList.size());
            LOG.info("失败的公司有"+JSONObject.toJSONString(failsCorpidList));
        }
        return JSON.toJSONString(response);
    }

    /**
     * 重新注册钉钉回调事件
     * 执行套餐有效期的公司
     *
     * @param dingtalkReRegistCallBackDTO
     * @param br
     * @return
     * @throws XbbException
     */
    @RequestMapping(value = "/eventChange/reRegisters", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String eventChangeReRegister(@RequestBody @Valid DingtalkReRegistCallBackDTO dingtalkReRegistCallBackDTO, BindingResult br) throws XbbException {
        if (!proBaseConfig.getXbbCode().equals(dingtalkReRegistCallBackDTO.getXbbCode())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100006, SystemErrorCodeEnum.API_ERROR_100006.getMsg());
        }
        XbbResponse<BaseVO> response = new XbbResponse<>(new BaseVO());;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            long start = DateTimeUtil.getInt();
            LOG.warn("回调注册开始");
            List<String> corpidList = companyModel.getCorpidListByActive();
            // 有效期的公司
            if (CollectionsUtil.isEmpty(corpidList)) {
                return "无有效公司";
            }
            // 回调地址
            String url = Env.LOCAL_URL + Env.CALL_BACK_URL;
            List<String> callBackTag = getCallBackTag();
            List<JSONObject> failsCorpidList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            LOG.warn("回调注册开始"+corpidList.size());
            int i = 1;
            for ( String str : corpidList ) {
                LOG.warn("回调注册进行中"+i+"/"+corpidList.size());
                String accessToken = null;
                // 解除注册的回调事件，分开try catch是为了防止解除的错误导致后面的注册事件失败
                try {
                    accessToken = authHelper.getAccessToken(str);
                    EventChangeHelper.deleteEventChange(accessToken);
                } catch (OApiException e) {
                    if (e.getErrCode() == 71007) {
                        LOG.warn("回调地址已不存在！不需要删除,corpid = " + str);
                    } else {
                        LOG.error("解除注册的回调事件时出现了其他错误", e);
                    }

                }
                try {
                    EventChangeHelper.registerEventChange(accessToken,
                            callBackTag, Env.TOKEN, Env.ENCODING_AES_KEY, url);
                    i++;
                } catch (OApiException e) {
                    LOG.error("注册钉钉事件回调失败", e);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(str,e.getErrMsg());
                    failsCorpidList.add(jsonObject);
                }
            }
            LOG.warn("回调注册结束"+i+"/"+corpidList.size());
            LOG.warn("失败的公司有"+JSONObject.toJSONString(failsCorpidList));
            String s = "花费时间：" + (DateTimeUtil.getInt() - start) + "秒；";
            LOG.warn(s);
        }
        return JSON.toJSONString(response);
    }

    /***
     * 互动卡片回调注册
     *
     * @param baseDTO
     * @param br
     * @throws
     * @return java.lang.String
     * @author hongxiao
     * @date 2022-06-13 16:22
     * @since
     * @version
     */
    @RequestMapping(value = "/interactivecard/callback/register", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String interactiveCardRegisters(@RequestBody @Valid BaseDTO baseDTO, BindingResult br) throws XbbException {
        XbbResponse<BaseVO> response = new XbbResponse<>(new BaseVO());;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            LOG.info("互动卡片回调注册开始");
            String corpid = baseDTO.getCorpid();

            try {
                String accessToken = authHelper.getAccessToken(corpid);
                List<String> routeKeyList = getInteractiveCardRouteKey();
                for (String routeKey : routeKeyList) {
                    // 回调地址
                    String url = Env.LOCAL_URL + Env.INTERACTIVE_CARD_CALL_BACK_URL + routeKey;
                    EventChangeHelper.registerInteractiveCardCallback(accessToken,
                            Env.ENCODING_AES_KEY, url, routeKey, true);
                }
            } catch (OApiException e) {
                LOG.error("注册钉钉事件回调失败", e);
                response = new XbbResponse<>(new XbbException(e.getErrCode(), e.getErrMsg()));
            }
        }
        return JSON.toJSONString(response);
    }


    /*
     * 构建监听的事件类型,现在只监听通讯录事件回调 user_add_org : 通讯录用户增加 user_modify_org :
     * 通讯录用户更改 user_leave_org : 通讯录用户离职 org_admin_add ：通讯录用户被设为管理员
     * org_admin_remove ：通讯录用户被取消设置管理员 org_dept_create ： 通讯录企业部门创建
     * org_dept_modify ： 通讯录企业部门修改 org_dept_remove ： 通讯录企业部门删除 org_remove ：
     * 企业被解散
     */
    private List<String> getCallBackTag() {

        List<String> callBackTag = new ArrayList<>();
        callBackTag.add("user_add_org");
        callBackTag.add("user_modify_org");
        callBackTag.add("user_leave_org");
        callBackTag.add("org_admin_add");
        callBackTag.add("org_admin_remove");
        callBackTag.add("org_dept_create");
        callBackTag.add("org_dept_modify");
        callBackTag.add("org_dept_remove");
        callBackTag.add("org_remove");


        callBackTag.add("chat_add_member");
        callBackTag.add("chat_remove_member");
        callBackTag.add("chat_quit");
        callBackTag.add("chat_update_owner");
        callBackTag.add("chat_update_title");
        callBackTag.add("chat_disband");
        callBackTag.add("chat_template_change");
        // 酷应用
        callBackTag.add("im_cool_app_install");
        callBackTag.add("im_cool_app_uninstall");

        return callBackTag;
    }

    /**
     * 回调地址路由key
     */
    private List<String> getInteractiveCardRouteKey() {
        List<String> routeKey = new ArrayList<>();
        routeKey.add(Env.ROUTE_KEY_CARD_LIKE);
        routeKey.add(Env.ROUTE_KEY_CLOSE_TOP_CARD);
        return routeKey;
    }

}
